package com.zijidelu.luframework.base.dict;

import com.zijidelu.luframework.base.TypeCaster;
import com.zijidelu.luframework.base.exception.sys.DictTranslationException;
import com.zijidelu.luframework.base.model.BaseModel;
import lombok.Getter;

import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * 字典翻译编排。
 *
 * @author ZIJIDELU
 * @datetime 2025/11/8 19:12
 */
@Getter
public class DictMapping<D extends BaseModel, I, O> {
    private final Function<D, I> originField;
    private final BiConsumer<D, O> targetField;
    private final Class<? extends Dict<?, ?>> dictClass;
    private final boolean reverse;

    private DictMapping(Function<D, I> originField,
                        BiConsumer<D, O> targetField,
                        Class<? extends Dict<?, ?>> dictClass,
                        boolean reverse) {
        this.originField = originField;
        this.targetField = targetField;
        this.dictClass = dictClass;
        this.reverse = reverse;
    }

    /**
     * 创建一个字典翻译编排。
     * 该方法根据字典键进行翻译，而不是根据值。
     *
     * @param originField 源字段，用于提取字典键
     * @param targetField 目标字段，用于设置字典值
     * @param dictClass   字典枚举类，必须实现 IDict 接口
     * @return 新的 DictArrangement 实例
     */
    public static <D extends BaseModel, K, V, T extends Enum<T> & Dict<K, V>> DictMapping<D, K, V> fromKey(
            Function<D, K> originField,
            BiConsumer<D, V> targetField,
            Class<T> dictClass
    ) {
        return new DictMapping<>(originField, targetField, dictClass, false);
    }

    /**
     * 创建一个字典翻译编排。
     * 该方法根据字典值进行翻译，而不是根据键。
     *
     * @param originField 源字段，用于提取字典值
     * @param targetField 目标字段，用于设置字典键
     * @param dictClass   字典枚举类，必须实现 IDict 接口
     * @return 新的 DictArrangement 实例
     */
    public static <D extends BaseModel, K, V, T extends Enum<T> & Dict<K, V>> DictMapping<D, V, K> fromValue(
            Function<D, V> originField,
            BiConsumer<D, K> targetField,
            Class<T> dictClass
    ) {
        return new DictMapping<>(originField, targetField, dictClass, true);
    }

    /**
     * 执行翻译编排的核心逻辑。
     * 该方法负责从源字段提取值，根据字典进行翻译，然后将结果设置到目标字段。
     *
     * @param model 要处理的模型实例，必须实现 DataModel 接口
     */
    public void process(D model) {
        final I originFieldValue = originField.apply(model);
        if (originFieldValue == null) return;

        final Dict<?, ?> dictItem = findDictItem(originFieldValue);

        final O targetFieldValue = TypeCaster.cast(reverse ? dictItem.getKey() : dictItem.getValue());

        targetField.accept(model, targetFieldValue);
    }

    /**
     * 私有辅助方法：封装查找、日志和异常逻辑
     * <p>
     * 此方法无需严格类型安全，因为字典项的键和值类型是未知的。
     * 但是，在调用时，必须确保传递的键或值与字典项的类型兼容。
     *
     * @param keyOrValue 要查找的键或值，类型为 Object 以支持泛型
     * @return 找到的字典项
     */
    private Dict<?, ?> findDictItem(I keyOrValue) {
        final Dict<?, ?> dictItem;

        if (reverse) {
            dictItem = Dict.getByValue(TypeCaster.cast(dictClass), TypeCaster.cast(keyOrValue));
            if (dictItem == null) {
                throw DictTranslationException.valueNotFound(dictClass, keyOrValue);
            }
        } else {
            dictItem = Dict.getByKey(TypeCaster.cast(dictClass), TypeCaster.cast(keyOrValue));
            if (dictItem == null) {
                throw DictTranslationException.keyNotFound(dictClass, keyOrValue);
            }
        }

        return dictItem;
    }

}
